狂神JUC并发编程笔记 |
您所在的位置:网站首页 › juc 狂神 › 狂神JUC并发编程笔记 |
视频来自: https://www.bilibili.com/video/BV1B7411L7tE?p=5&spm_id_from=pageDriver 看到一个新东西不会,狂神会先看源码 JUC = java.util.conrrunent 创建线程的三种方式 extends thread, implement runnable, implement callable接口 常规的实现并发的方式,用synchronized,以及 new Thread(new Runnable() { @Override public void run() { String a = "run 1"; } }).start();上面代码在java 8以后可用lambda表达式: new Thread(() -> { String a = "run 1"; } }).start();锁的实现方式,Lock三部曲 1、 new ReentrantLock(); 2. lock.lock(); //加锁 3. try { xxx} catch {} finaly { lock.unlock()}//解锁 池化技术: 事先准备好资源,有人要用,就来我这里拿,用完之后还给我 默认大小: 2 最小值、最大值 线程池的好处:1. 降低资源消耗 2.提高响应的速度 3.(因为放到池子里了)方便管理 线程复用,控制最大并发数,管理线程 线程池: 三大方法,7种参数,4种拒绝策略 线程池三大方法 public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())); } public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); } public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); } 线程池七大参数 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {按参数顺序依次对应: 1.核心线程数 线程池里面最小的活跃线程数 2.最大线程数 线程池里面最大的活跃线程数 3.保活时间 线程不工作的最大时间,超时了没有人调用就会释放 4.时间单位 超时用的时间单位 5.工作队列: 用来储存要执行,但是未执行的线程(也即为阻塞的线程) 6.线程工厂 用来创建线程的,一般不用动 7.拒绝策略 线程池的执行流程,任务来了先放入核心线程池里面,其次放入非核心线程,否则进入工作队列 Volitale 不保证原子性 public class VolatileNotAtomicTest { private volatile static int num = 0; public static void add() { ++num;// ++num和num++都是非原子操作,一行对应3-4行汇编指令 } public static void main(String[] args) { for (int i = 1; i { for(int j= 0; j < 1000; j++) { add(); } }).start(); } while (Thread.activeCount() > 2) { Thread.yield(); } System.out.println(num); // num 一般小于 20000,因为没有原子性 } }保证有序性的原理是指令重排序,保证可见性的原理是MESE一致性缓存协议,以及CPU嗅探机制 深入理解CASUnsafe类: 因为java无法操作内存,而c++可以,Unsafe是Java的后门,通过这个类,调用native方法,来操作内存 public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } public final int getAndAddInt(Object this, long valueOffset, int increment) { int previousValue ; do { previousValue = this.getIntVolatile(this, valueOffset); } while(!this.compareAndSwapInt(this, valueOffset, previousValue, previousValue + increment)); // 如果当前对象内存的值(this + valueOffset) 还是和我期望的值 previousValue相等 // 那么将该对象内存值改为 previousValue + increment // compareAndSwapInt 是CPU原语言,操作很快 return var5; }上述自旋操作, 池的最大线程数到底该如何定义CPU 密集型: 几核,就是几, 可以保持CPI的效率最高,如下图,CPU核 = 逻辑处理器数量,即12个 如何获取核数: System.out.println(Runtime.getRuntime().availableProcessors());IO 密集型: 判断你程序中十分耗IO的线程,有多少个,比如有15个任务比较耗费线程,那么就设置最大线程数为两倍,30个 四大函数式接口标明了@FunctionalInterface的接口 "lambda表达式就是为了优化匿名内部类而生" Consumer, Function, Predicate, Supplier 只要是函数式接口,就能用lambda表达式简化 BlockingQueue四组APIadd, remove element(返回队首)会抛出异常 offer,poll, peek(返回队首) 不会抛出异常 put,take 一直阻塞,string.sout offer("element", 2, Timeunit.SECOND),poll(2, Timeunit.SECOND) 超时(2S)退出 ArrayBlockingQueue 基于数组结构的队列 LinkedBlockingQueue 基于链表结构的队列 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |